﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GOFconsole
{
    public class Chapter9_Prototype
    {
        public void PrototypeTest()
        {
            //概念
            ConcretePrototype1 p1 = new ConcretePrototype1("Iaaaa");
            ConcretePrototype1 copy1 = (ConcretePrototype1)p1.Clone();
            Console.WriteLine("Cloned:{0}",copy1.Id);
            //DEMO
            Resume a = new Resume("大鸟");
            a.SetPersonalInfo("男", "28");
            a.SetWorkExperience("2013-2015","XX公司");

            //**如果用Resume b=a; 只是传了引用，并没有复制一个a出来。相当于b的纸上写着，简历在a那里一样，没有实际内容。
            Resume b = (Resume)a.Clone();                 //只要调用CLONE方法就可以实现新简历的生成
            b.SetWorkExperience("2014-2016", "YY公司");   //并且可以再次修改细节

            a.Display();
            b.Display();
            Console.WriteLine("a = b :" + Object.ReferenceEquals(a, b));

            //浅复制
            ResumeShallowCopy aa = new ResumeShallowCopy("大鸟");
            aa.SetPersonalInfo("男", "28");
            aa.SetWorkExperience("2013-2015", "XX公司");

            ResumeShallowCopy bb = (ResumeShallowCopy)aa.Clone();               
            bb.SetWorkExperience("2014-2016", "YY公司");

            aa.Display();       //结果显示：两次都是最后一次设置的值 YY公司
            bb.Display();       //这表明对引用类型只是复制了引用，对引用的对象还是指向了原来的对象，所以两个都变了
            Console.WriteLine("aa.we = bb.we :" + Object.ReferenceEquals(aa.we, bb.we));

            //深复制
            ResumeDeepCopy aaa = new ResumeDeepCopy("大鸟");
            aaa.SetPersonalInfo("男", "29");
            aaa.SetWorkExperience("2012-2016", "XX公司");

            ResumeDeepCopy bbb = (ResumeDeepCopy)aaa.Clone();
            bbb.SetWorkExperience("2013-2016", "YY公司");

            aaa.Display();       //结果显示：两次结果已经不同了，说明bbb是复制成新的对象了而不是引用aaa
            bbb.Display();
            Console.WriteLine("aaa.we = bbb.we:" + Object.ReferenceEquals(aaa.we, bbb.we)); 
        }
    }

#region 模型
    //原型类
    abstract class Prototype
    {
        private string id;

        public Prototype(string id)
        {
            this.id = id;
        }

        public string Id
        {
            get { return id; }
        }

        public abstract Prototype Clone();
    }
    //具体原型类
    class ConcretePrototype1 : Prototype
    {
        public ConcretePrototype1(string id)
            : base(id)
        { }

        public override Prototype Clone()
        {
            //浅复制:创建一个新对象，将当前对象的非静态字段复制到新对象，
            //如果字段是值类型的，则对该字段执行逐位复制。如果是引用类型，则复制引用但不复制引用的对象。
            //***因此，原始对象及副本引用同一个对象。***
            return (Prototype)this.MemberwiseClone();
        } 
    }
#endregion 

    #region 浅复制
    //示例
    //.NET提供了ICloneable接口，其中唯一的方法Clone()，只要实现这个接口就能完成原型模式
    //简历类
    class Resume : ICloneable
    {
        private string name;
        private string sex;
        private string age;
        private string timeArea;
        private string company;

        public Resume(string name)
        {
            this.name = name;
        }

        public void SetPersonalInfo(string sex, string age)
        {
            this.sex = sex;
            this.age = age;
        }

        public void SetWorkExperience(string timeArea, string company)
        {
            this.timeArea = timeArea;
            this.company = company;
        }

        public void Display()
        {
            Console.WriteLine("{0} {1} {2}",name,sex,age);
            Console.WriteLine("工作经历：{0} {1}", timeArea,company);
        }

        public object Clone()
        {           
            return (Object)this.MemberwiseClone();
        }
    }

    //浅复制
    class WorkExperience
    {
        private string timeArea;

        public string TimeArea
        {
            get { return timeArea; }
            set { timeArea = value; }
        }
        private string company;

        public string Company
        {
            get { return company; }
            set { company = value; }
        }
    }

    class ResumeShallowCopy : ICloneable
    {
        private string name;
        private string sex;
        private string age;
        public WorkExperience we;

        public ResumeShallowCopy(string name)
        {
            this.name = name;
            we = new WorkExperience();
        }

        public void SetPersonalInfo(string sex, string age)
        {
            this.sex = sex;
            this.age = age;
        }

        public void SetWorkExperience(string timeArea, string company)
        {
            we.TimeArea = timeArea;
            we.Company = company;
        }

        public void Display()
        {
            Console.WriteLine("{0} {1} {2}", name, sex, age);
            Console.WriteLine("工作经历：{0} {1}", we.TimeArea, we.Company);
        }

        public object Clone()
        {
            //浅复制:创建一个新对象，将当前对象的非静态字段复制到新对象，
            //如果字段是值类型的，则对该字段执行逐位复制。如果是引用类型，则复制引用但不复制引用的对象。
            //***因此，原始对象及副本引用同一个对象。***
            //如果简历类中有对象引用，那么引用的对象数据是不会被克隆过来的。
            return (Object)this.MemberwiseClone();
        }
    }
    #endregion 

    #region 深复制
    //深复制
    //让工作经历类也实现ICloneabe接口
    class WorkExperienceDeep:ICloneable
    {
        private string timeArea;

        public string TimeArea
        {
            get { return timeArea; }
            set { timeArea = value; }
        }
        private string company;

        public string Company
        {
            get { return company; }
            set { company = value; }
        }

        public object Clone()
        {
            return (Object)this.MemberwiseClone();
        }
    }

    class ResumeDeepCopy : ICloneable
    {
        private string name;
        private string sex;
        private string age;
        public WorkExperienceDeep we;

        public ResumeDeepCopy(string name)
        {
            this.name = name;
            we = new WorkExperienceDeep();
        }
        private ResumeDeepCopy(WorkExperienceDeep we)
        {
            //提供Clone方法调用的私有构造函数，以便克隆"工作经历"的数据
            this.we=(WorkExperienceDeep)we.Clone();           
        }

        public void SetPersonalInfo(string sex, string age)
        {
            this.sex = sex;
            this.age = age;
        }

        public void SetWorkExperience(string timeArea, string company)
        {
            we.TimeArea = timeArea;
            we.Company = company;
        }

        public void Display()
        {
            Console.WriteLine("{0} {1} {2}", name, sex, age);
            Console.WriteLine("工作经历：{0} {1}", we.TimeArea, we.Company);
        }

        public object Clone()
        {
            //调用私有的构造方法，让"工作经历"克隆完成，然后再给这个简历对象的相关字段赋值
            //最终返回一个深复制的简历对象 
            //*** (没有达到效果，暂时不知道为啥) 15.5.26
            //return 的是obj 不是this......终于发现原因 15.6.30
            ResumeDeepCopy obj = new ResumeDeepCopy(this.we);
            obj.name = this.name;
            obj.sex = this.sex;
            obj.age=this.age;
            return obj;
        }
    }
#endregion 

}
